package jadeCW.behaviour;

import jade.core.AID;
import jade.core.behaviours.Behaviour;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jadeCW.PatientAgent;
import jadeCW.output.Printer;

import java.util.List;


/**
 * Find Appointment Owner behaviour class
 * 
 * @author br08, dac108, dv08
 */
public class FindAppointmentOwner extends Behaviour {
	/**
	 * Type identifier for message
	 */
	public static final String TYPE = "find-appointment";

	/**
	 * Generated serialisation ID
	 */
	private static final long serialVersionUID = 7640124807840659636L;

	private int step = 0;
	private int preferred;
	private MessageTemplate template;

	@Override
	public void action() {
		// must be run on a patient
		if (!(myAgent instanceof PatientAgent)) {
			return;
		}

		PatientAgent patient = (PatientAgent) myAgent;

		// get the current and most preferred appointments for the patient
		int current = patient.getAppointment();
		this.preferred = patient.getMostPreferredAppointment(current);

		int currentPreference = patient.getPreference(current);
		int desiredPreference = patient.getPreference(this.preferred);
		
		// if we have our most preferred appointment, end the behaviour
		if (currentPreference == desiredPreference) {
			this.step = 2;
			return;
		}

		switch (this.step) {
		case 0:
			List<DFAgentDescription> hospitals = patient
					.getAppointmentAllocators();

			// if we have no hospitals, finish
			if (hospitals.size() == 0) {
				this.step = 2;
				return;
			}

			// create a request
			ACLMessage request = new ACLMessage(ACLMessage.REQUEST);

			// send it to all recorded hospitals
			for (DFAgentDescription hospital : hospitals) {
				request.addReceiver(hospital.getName());
			}

			// ask to find the owner of the preferred appointment
			request.setContent(String.valueOf(this.preferred));
			request.setConversationId(TYPE);
			request.setReplyWith(TYPE + System.currentTimeMillis());

			// prepare the template to get responses
			this.template = MessageTemplate.and(MessageTemplate
					.MatchConversationId(TYPE), MessageTemplate
					.MatchInReplyTo(request.getReplyWith()));

			Printer.printFindOwnerSend(patient, this.preferred, hospitals);
			
			// send the request
			patient.send(request);

			step = 1;
			break;
		case 1:
			// receive a response
			ACLMessage reply = patient.receive(this.template);

			if (reply != null) {
				switch (reply.getPerformative()) {

				// if the response is a proposal
				case ACLMessage.PROPOSE:
					AID owner = new AID(reply.getContent(), AID.ISGUID);

					Printer.printFindOwnerReceiveProposal(patient,
							this.preferred, owner);

					// if the patient has already found this owner, he will
					// reject us again so stop
					if (owner.equals(patient.getPreferredOwner())) {
						patient.removePreference(this.preferred);
						
						Printer.printFindOwnerReceiveSame(patient, this.preferred);
						
						step = 0;
						return;
					}

					// if the patient doesn't already own the appointment
					if (!patient.getAID().equals(owner)) {

						// store the preferred appointment and owner
						patient.setPreferredAppointment(this.preferred, owner);
						
						// start a swap proposal
						patient.addBehaviour(new ProposeSwap());
					}

					break;
				// if the response is a refusal
				case ACLMessage.REFUSE:
					// remove the preference for that appointment and start
					// again
					patient.removePreference(this.preferred);
					
					Printer.printFindOwnerReceiveRefusal(patient, this.preferred);
					
					step = 0;
					return;
				}

				this.step = 2;
			} else {
				block();
			}
		}
	}

	@Override
	public boolean done() {
		return (this.step == 2);
	}
}
